/**
 * Created by Forcs on 16/4/11.
 */

var DbService = require('./db/DbService');
var events = require('events');
var util = require('util');
var config = require('./app.config');
var BaseController = require('./controllers/BaseController');
var log4js = require('log4js');
var LogUtils = require('./utils/log/LogUtils');

var AppLogs = require('./models/logs/AppLogs');
var ContentLogsResolver = require('./resolvers/ContentLogsResolver');
var AppLogsResolver = require('./resolvers/AppLogsResolver');
var coreData = require('./resolvers/CoreData');

var co = require('co');

var Application = function (context) {
  var _self = this;
  _self.$context = context;
  _self._options = config.application || {};
  _self._dbService = new DbService(_self._options.db || {});
  _self._controllers = {};
  _self._services = {};
  _self.status = {
    currentLogType: '',
    currentProgress: 0.00,
    totalSize: 0,
    current: 0
  };

  events.EventEmitter.call(_self);

  LogUtils.debug = _self._options.debug;
  
  _self._dbService.registerModels(config.models || {});

  var registerServices = function (self, servicesConfig) {
    for (var key in servicesConfig) {
      if (!servicesConfig.hasOwnProperty(key)) {
        continue;
      }
      self._services[key] = servicesConfig[key]
    }
  };

  var registerControllers = function (self, controllersConfig) {
    var controllers = controllersConfig;
    for (var key in controllers) {
      if (!controllers.hasOwnProperty(key)) {
        continue;
      }
      var instance = new controllers[key]();
      BaseController.call(instance);
      util.inherits(controllers[key], BaseController);
      instance.$application = self;
      instance.$context = self.$context;
      instance.onCreate();
      self._controllers[key] = instance;
      self.$context.use('/' + key, instance.router())
    }
  };

  var initLog = function (self, logConfig, defLog) {
    log4js.configure(logConfig);
    if (logConfig.loggerTags) {
      logConfig.loggerTags.forEach(function (item) {
        var log = log4js.getLogger(item);
        self.$context.use(log4js.connectLogger(log, {level: 'INFO'}));
      });
    } else {
      var logDef = log4js.getLogger(defLog);
      self.$context.use(log4js.connectLogger(logDef, {level: 'INFO'}));
    }
  };

  initLog(_self, _self._options.log || {});

  registerServices(_self, config.services || {});
  registerControllers(_self, config.controllers || {});
};

util.inherits(Application, events.EventEmitter);

Application.prototype.start = function () {
  var _self = this;
  _self._dbService.ready(function () {
    _self.db = _self._dbService.db();
    for (var key in _self._controllers) {
      if (!_self._controllers.hasOwnProperty(key)) {
        continue;
      }
      _self._controllers[key].onStart();
    }

    co(function * () {
      yield new AppLogsResolver(AppLogs).resolve();
      yield new ContentLogsResolver(AppLogs).resolve();
      LogUtils.info('app start.');
      _self.emit('start');
    }).catch(function (err) {
      LogUtils.error('err' + err);
      _self.emit('err', err);
    });
  });
};

Application.prototype.getService = function (name) {
  return new this._services[name](this, this.$context);
};

module.exports = Application;

